﻿using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Text;
using System.Xml.Linq;

namespace MOMKeLABS.Web
{
    [ServiceContract(Namespace = "")]
    [SilverlightFaultBehavior]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service
    {

        #region DAL

        /// <summary>
        /// TODO
        /// </summary>
        [OperationContract]
        public void LogException(Exception ex, string failPoint)
        {}

        /// <summary>
        /// Save the users settings back to the DB
        /// </summary>
        /// <param name="usrSettings"></param>
        /// <param name="email"></param>
        /// <returns></returns>
        [OperationContract]
        public bool SaveUserSettings(Base.UserSettings usrSettings, string email)
        {
            DataClassesDataContext db = new DataClassesDataContext();

            UserSetting settings = db.UserSettings.Single(p => p.Email.Equals(email));

            if (settings == null)
            {
                // there are no settings for this user (this should never happen)
                // we need to create them an entry in the DB. This helps to preserve the
                // resiliance of the DB

                UserSetting tmp = new UserSetting()
                {
                    Email = email
                };

                db.UserSettings.InsertOnSubmit(tmp);

                db.SubmitChanges();

                settings = tmp;
            }

            try
            {

                XDocument doc = new XDocument();

                XmlSerializer serializer = new XmlSerializer(typeof(Base.UserSettings));

                XmlWriter writer = doc.CreateWriter();

                serializer.Serialize(writer, usrSettings);

                writer.Close();

                settings.Settings = doc.Root;

                db.SubmitChanges();
            }
            catch (Exception ex)
            {
                LogException(ex, "Save user settings: Line 77");
                return false;
            }

            return true;
            
        }


        /// <summary>
        /// returns the settings object from the database
        /// </summary>
        /// <param name="email"></param>
        /// <returns></returns>
        [OperationContract]
        public Base.UserSettings GetUserSettings(string email)
        {
            DataClassesDataContext db = new DataClassesDataContext();

            UserSetting settings = db.UserSettings.Single(p => p.Email.Equals(email));

            if (settings == null)
            {
                // this user doesn't have any settings so we need to create them some and return that
                return new Base.UserSettings();
            }

            if (settings.Settings == null)
            {
                // this user dosn't have any settings to we need to create them some
                return new Base.UserSettings();
            }

            // Attempte to desreialize the settings form the DB
            try
            {
                XmlSerializer deserializer = new XmlSerializer(typeof(Base.UserSettings));

                MemoryStream stream = new MemoryStream();

                settings.Settings.Save(stream);


                return deserializer.Deserialize(stream) as Base.UserSettings;

            }catch(Exception ex)
            {
                LogException(ex, "GetUserSettings: Line: 126");
                return new Base.UserSettings();
            }
                        
        }

        /// <summary>
        /// Look up a user and attempt to authenticate them agaisnt the database
        /// </summary>
        /// <param name="Email">The email of the user to look up</param>
        /// <param name="Token">Their security token to use as a mean of validation</param>
        /// <returns></returns>
        [OperationContract]
        public UserIdentity Login(string Email, string Token)
        {
            DataClassesDataContext db = new DataClassesDataContext();

            UserIdentity identity = db.UserIdentities.Single(p => p.Email.Equals(Email));

            // the user cound not be found in the DB so we kick them out. 
            if (identity == null)
            {
                return null;
            }

            // They have supplied an incorrect token so we should kick them out too
            if (identity.AuthToken != Token)
            {
                return null;
            }

            // This token has already been used for a login. 
            if (!identity.TokenValid)
            {
                return null;
            }

            // if we get here, it means the user exists, they have a correct and valid token so we can authenticate them

            // we must invalidate their token now so it can't be used again
            InvalidateToken(Email);

            return identity;
            
        }

        /// <summary>
        /// Invalidate the token of a user once they have logged in
        /// </summary>
        /// <param name="Email">The email of the user who's token needs to be invalidated</param>
        /// <returns></returns>
        private bool InvalidateToken(string Email)
        {
            DataClassesDataContext db = new DataClassesDataContext();

            UserIdentity ui = db.UserIdentities.Single(p => p.Email.Equals(Email));

            if (ui == null)
            {
                return false;
            }

            ui.TokenValid = false;

            try
            {
                db.SubmitChanges();
            }
            catch (Exception)
            {
                return false;
            }

            return true;
        }



        #endregion DAL

    }
}
